﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using System.Timers;
using System.Windows.Threading;

namespace BatteryUptime
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        //Represents our tray icon
        private System.Windows.Forms.NotifyIcon batteryMonitorIcon = new System.Windows.Forms.NotifyIcon();
        private DispatcherTimer updateTimer = new DispatcherTimer();
        private bool hasBeenPluggedIn = false;
        private int uptime = 0;
        private WindowState lastWindowState = WindowState.Normal;
        private DateTime LastChargeDate = DateTime.Now;
        private const string BatteryLogFile = "BatteryLog.txt";

        public MainWindow()
        {
            InitializeComponent();

            //event listeners
            this.Closed += new EventHandler(MainWindow_Closed);
            this.StateChanged += new EventHandler(OnStateChanged);
            ExitMenuItem.Click += new RoutedEventHandler(ExitMenuItem_Click);
            AboutMenuItem.Click += new RoutedEventHandler(AboutMenuItem_Click);

            //Set up the tray icon
            batteryMonitorIcon.BalloonTipText = "";
            batteryMonitorIcon.BalloonTipTitle = "";
            batteryMonitorIcon.Text = "Battery Uptime Monitor";
            batteryMonitorIcon.Icon = new System.Drawing.Icon("Images/battery_100.ico");
            batteryMonitorIcon.Click += new EventHandler(batteryMonitorIcon_Click);
            batteryMonitorIcon.Visible = true;
            System.Windows.Forms.ContextMenuStrip strip = new System.Windows.Forms.ContextMenuStrip();
            batteryMonitorIcon.ContextMenuStrip = strip;

            //load any previous data
            try
            {
                using (TextReader reader = new StreamReader(BatteryLogFile))
                {
                    Int32.TryParse(reader.ReadLine(), out uptime);
                    DateTime.TryParse(reader.ReadLine(), out LastChargeDate);
                    Boolean.TryParse(reader.ReadLine(), out hasBeenPluggedIn);
                }
            }
            catch (Exception ex)
            {
                //lazy me
            }

            //set up timer
            updateTimer.Interval = new TimeSpan(0, 0, 1, 0, 0);
            updateTimer.Tick += new EventHandler(UpdateBatteryStatus);
            updateTimer.Start();
            UpdateBatteryStatus(this, EventArgs.Empty);
        }

        void AboutMenuItem_Click(object sender, RoutedEventArgs e)
        {
            AboutWindow aw = new AboutWindow();
            aw.ShowDialog();
        }

        void ExitMenuItem_Click(object sender, RoutedEventArgs e)
        {
            Application.Current.Shutdown();
        }

        /// <summary>
        /// Updates the battery status
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void UpdateBatteryStatus(object sender, EventArgs e)
        {
            //update uptime information
            System.Windows.Forms.PowerStatus status = System.Windows.Forms.SystemInformation.PowerStatus;
            BatteryStatusProgressBar.Value = Math.Round(status.BatteryLifePercent * 100);
            BatteryPercentText.Text = Math.Round(status.BatteryLifePercent * 100, 2).ToString() + "%";

            //if we're not at 99% charge, update data.  Otherwise, reset everything.
            if (BatteryStatusProgressBar.Value < 98.9)
            {
                uptime += updateTimer.Interval.Minutes;

                //check charging status
                if (status.BatteryChargeStatus == System.Windows.Forms.BatteryChargeStatus.Charging)
                {
                    hasBeenPluggedIn = true;
                }
            }
            else
            {
                //reset everything
                hasBeenPluggedIn = false;
                uptime = 0;
                LastChargeDate = DateTime.Now;
            }

            //do we need to display a notification indicating that the system has been plugged in?
            if (hasBeenPluggedIn)
            {
                HasBeenPluggedInTextBlock.Visibility = System.Windows.Visibility.Visible;
            }
            else
            {
                HasBeenPluggedInTextBlock.Visibility = System.Windows.Visibility.Collapsed;
            }

            //display battery status
            PluginStatusTextBlock.Text = status.BatteryChargeStatus.ToString() + "...";

            //display uptime minutes
            string uptimeStr = FormatTimespan(new TimeSpan(0, 0, uptime, 0));
            MinutesOnTextBlock.Text = uptimeStr;

            //display time since last charge
            string lastChargeStr = FormatTimespan(DateTime.Now.Subtract(LastChargeDate));
            TimeLastChargeTextBlock.Text = lastChargeStr;

            //don't forget to update the tooltip icon as well
            batteryMonitorIcon.Text = String.Format("Last Charge: {0}\nUptime: {1}", lastChargeStr, uptimeStr);
            
            //visual aid for battery status
            batteryMonitorIcon.Icon = GetBatteryIcon(status);

            //write uptime information to file
            TextWriter writer = new StreamWriter(BatteryLogFile, false);
            writer.WriteLine(String.Format("{0}", uptime));
            writer.WriteLine(DateTime.Now.ToLocalTime());
            writer.WriteLine(String.Format("{0}", hasBeenPluggedIn));
            writer.Close();
        }

        /// <summary>
        /// Returns a battery icon to match the current power state
        /// </summary>
        /// <param name="status"></param>
        /// <returns></returns>
        private System.Drawing.Icon GetBatteryIcon(System.Windows.Forms.PowerStatus status)
        {
            if (status.BatteryLifePercent < 0.1)
            {
                return new System.Drawing.Icon("Images/battery_000.ico");
            }
            else if(status.BatteryLifePercent < 0.33)
            {
                return new System.Drawing.Icon("Images/battery_025.ico");
            }
            else if(status.BatteryLifePercent < 0.66)
            {
                return new System.Drawing.Icon("Images/battery_050.ico");
            }
            else if(status.BatteryLifePercent < 0.88)
            {
                return new System.Drawing.Icon("Images/battery_075.ico");
            }
            else
            {
                return new System.Drawing.Icon("Images/battery_100.ico");
            }
        }

        /// <summary>
        /// Creates a string in the format {days}, {hours}, {minutes}
        /// </summary>
        /// <param name="span"></param>
        /// <returns></returns>
        private string FormatTimespan(TimeSpan span)
        {
            string ret = "";

            //start with days component
            if (span.Days > 1)
            {
                ret += String.Format("{0} days, ", span.Days);
            }
            else if (span.Days > 0)
            {
                ret += String.Format("{0} day, ", span.Days);
            }
            else if (span.Hours > 1)
            {
                ret += String.Format("{0} hours, ", span.Hours);
            }
            else if (span.Hours > 0)
            {
                ret += String.Format("{0} hour, ", span.Hours);
            }

            //then minutes
            ret += String.Format("{0} minutes", span.Minutes);
            return ret;
        }

        /// <summary>
        /// Perform some house cleaning before we close shop
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void MainWindow_Closed(object sender, EventArgs e)
        {
            batteryMonitorIcon.Dispose();
            batteryMonitorIcon = null;
        }

        /// <summary>
        /// Minimizes the app to the task bar
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        void OnStateChanged(object sender, EventArgs args)
        {
            if (WindowState == WindowState.Minimized)
            {
                Hide();
                if (batteryMonitorIcon != null)
                    batteryMonitorIcon.ShowBalloonTip(2000);
            }
            else
                lastWindowState = WindowState;
        }
        void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs args)
        {
            CheckTrayIcon();
        }

        void batteryMonitorIcon_Click(object sender, EventArgs e)
        {
            Show();
            WindowState = lastWindowState;
        }
        void CheckTrayIcon()
        {
            ShowTrayIcon(!IsVisible);
        }

        void ShowTrayIcon(bool show)
        {
            if (batteryMonitorIcon != null)
                batteryMonitorIcon.Visible = show;
        }
    }
}
